Analysis of Senator Stock Trading

Patrick Cao

Introduction

Insider trading, or trading financial assets using information that is not open to the public, is punishable by law in the United States. It is a serious violation -- a maximum penalty of 20 years in prison, and up to $20 million in fines. The Securities and Exchange Commission (SEC) is responsible for identifying and conducting investigations regarding insider trading.

With that being said, U.S. senators (and other congresspeople) often have access to information about upcoming policies or laws before the general public, yet are still allowed to trade securities. Senators, however, must disclose their trades publicly. More recently, a few senators have been investigated by the SEC for insider trading using nonpublic knowledge given to them about the COVID-19 pandemic. With the rise in popularity of investing, senator stock trading patterns has become to the public's attention. You may have seen posts on the internet implying that there is rampant insider trading going on in the senate. For example, take this post on Reddit that was upvoted over 30,000 times: https://www.reddit.com/r/dataisbeautiful/comments/gjlvnd/.

Is insider trading in the senate as rampant as this post suggests? This tutorial aims to identify potential insider trading patterns by the U.S. senate. In order to answer this question, we will be using data from https://senatestockwatcher.com/, which itself compiles data from https://efdsearch.senate.gov/. efdsearch.senate.gov does not have an official API, and scraping each page would be extremely tedious. Senate stock watcher aggregates financial disclosures from all senators into one nice dataset.

Let's first start by downloading the dataset. While Senate Stock Watcher provides an API for up to date datasets, we can just download a csv file as well. Download the "All Transactions" csv file from https://senatestockwatcher.com/api.html.

Let's load that into a pandas dataframe.

In [43]:
import pandas as pd
import numpy as np
import datetime

df = pd.read_csv('all_transactions.csv')
df.head()
Out[43]:
transaction_date owner ticker asset_description asset_type type amount comment senator ptr_link
0 11/16/2020 Spouse BA The Boeing Company Stock Purchase $15,001 - $50,000 R Pat Roberts https://efdsearch.senate.gov/search/view/ptr/b...
1 11/16/2020 Spouse V Visa Inc. Stock Purchase $15,001 - $50,000 555 Pat Roberts https://efdsearch.senate.gov/search/view/ptr/b...
2 11/24/2020 Spouse COST Costco Wholesale Corporation Stock Purchase $15,001 - $50,000 555 Pat Roberts https://efdsearch.senate.gov/search/view/ptr/b...
3 11/04/2020 Spouse COST Costco Wholesale Corporation Stock Sale (Full) $15,001 - $50,000 555 Pat Roberts https://efdsearch.senate.gov/search/view/ptr/b...
4 11/09/2020 Spouse BA The Boeing Company Stock Sale (Full) $15,001 - $50,000 sep Pat Roberts https://efdsearch.senate.gov/search/view/ptr/b...

Let's clean this up a little by limiting and purchases and sales only, and dropping unnecessary columns.

In [44]:
start_date = '2016-01-01'
end_date = '2020-11-01'

# Turn transaction_date from string into datetime
df['transaction_date'] = pd.to_datetime(df['transaction_date'])

# Remove (Full) and (Partial) after Sale type
df['type'] = df['type'].apply(lambda x: str(x).split()[0])

# Limit to only purchases and sales
df = df[(df['type'] == 'Purchase') | (df['type'] == 'Sale')]

# limit the dataset to a date range
df = df[(df['transaction_date'] > start_date) & (df['transaction_date'] < end_date)]

df = df.drop(['asset_description', 'comment', 'ptr_link'], axis=1)
df.head()
Out[44]:
transaction_date owner ticker asset_type type amount senator
76 2020-10-13 Joint -- Corporate Bond Sale $1,001 - $15,000 Sheldon Whitehouse
78 2019-04-05 Spouse NVS Stock Sale $1,001 - $15,000 William Cassidy
79 2020-10-16 Child NVDA Stock Purchase $1,001 - $15,000 Ron L Wyden
80 2020-10-16 Child WDAY Stock Purchase $1,001 - $15,000 Ron L Wyden
81 2020-10-16 Child NVDA Stock Purchase $1,001 - $15,000 Ron L Wyden

We got our senator stock trading data, but now we need actual historical market data to visualize these trades. Let's use yfinance, a python Yahoo! Finance library, to get historical market data on SPY, an ETF tracking the S&P500.

In [45]:
import yfinance as yf

spy = yf.Ticker('SPY')
spy_hist = spy.history(period='max')
spy_hist.tail()
Out[45]:
Open High Low Close Volume Dividends Stock Splits
Date
2020-12-07 369.019989 369.619995 367.720001 369.089996 48944300 0.0 0
2020-12-08 367.720001 370.779999 367.670013 370.170013 42458900 0.0 0
2020-12-09 370.880005 371.049988 365.950012 366.850006 74098300 0.0 0
2020-12-10 365.369995 367.859985 364.429993 366.730011 57617300 0.0 0
2020-12-11 364.899994 366.740204 363.260010 366.140015 49692479 0.0 0

Neat! Now we can start putting these two things together.

Exploratory Data Analysis

Senator Data

Let's take an initial look at the data. It would be interesting to see the most traded stocks, the most active senators, or the average value of each trade.

In [46]:
import matplotlib.pyplot as plt

# number of trades by senators
num_trades = df.groupby('senator').count().sort_values(by='transaction_date', ascending=False).head(10)
plt.title('Top 10 Most Active Senators')
plt.xlabel('Total Number of Trades')
plt.ylabel('Senator')
plt.barh(num_trades.index, num_trades['transaction_date'])
plt.show()

# number of trades by ticker
trades_by_ticker = df[df['ticker'] != '--'].groupby('ticker').count().sort_values(by='transaction_date', ascending=False).head(20)
plt.title('Top 20 Most Traded Stocks')
plt.xlabel('Total Number of Trades')
plt.ylabel('Ticker')
plt.barh(trades_by_ticker.index, trades_by_ticker['transaction_date'])
plt.show()

# values of trades
trade_val = df.groupby('amount').count().sort_values(by='transaction_date', ascending=False)
plt.title('Value of Trades')
plt.xlabel('Number of Trades')
plt.ylabel('Value of Trade ($)')
plt.barh(trade_val.index, trade_val['transaction_date'])
plt.show()

It looks like most trades by senators are small -- under $15,000 per trade -- and they like trading AAPL, which is coincidentally the largest market cap company in the world. There's a good mix of tech, pharma, communications, and retail stocks that are the most commonly traded in the senate. There's not too much insight we can pull from this, but it is interesting.

Let's now try to recreate the reddit post. We need to plot overall senator trading activity against the S&P500, or SPY.

It's a little tough to track performance exactly. The size of each trade isn't an exact number -- it's a range. Let's check out what kinds of values we're working with here.

In [47]:
df['amount'].unique()
Out[47]:
array(['$1,001 - $15,000', '$15,001 - $50,000', '$1,000,001 - $5,000,000',
       '$250,001 - $500,000', '$500,001 - $1,000,000',
       '$50,001 - $100,000', '$100,001 - $250,000',
       '$5,000,001 - $25,000,000'], dtype=object)

Yikes. The data doesn't have the exact value of securities traded, the best thing we can probably do is estimate the size of each trade by just taking the middle value of each trade. Unfortunately, the granularity of each bucket is pretty big, but we'll have to try and make do.

In [48]:
# Returns the average of the given bound
def getBounds(row):
    
    amount = row[0]
    trade_type = row[1]

    # This amount shows up once in the entire dataset. Let's just assume the trade is $50m for now. It won't affect our analysis too much.
    if amount == 'Over $50,000,000':
        return 5e7
    
    split = amount.split(' - ')
    lower = int(split[0][1:].replace(',', ''))
    upper = int(split[1][1:].replace(',', ''))
    mid = lower + ((upper - lower) / 2)

    if trade_type == 'Purchase':
        return mid
    return -mid

df['mid_amt'] = pd.Series(df[['amount', 'type']].apply(getBounds, axis=1))

df
Out[48]:
transaction_date owner ticker asset_type type amount senator mid_amt
76 2020-10-13 Joint -- Corporate Bond Sale $1,001 - $15,000 Sheldon Whitehouse -8000.5
78 2019-04-05 Spouse NVS Stock Sale $1,001 - $15,000 William Cassidy -8000.5
79 2020-10-16 Child NVDA Stock Purchase $1,001 - $15,000 Ron L Wyden 8000.5
80 2020-10-16 Child WDAY Stock Purchase $1,001 - $15,000 Ron L Wyden 8000.5
81 2020-10-16 Child NVDA Stock Purchase $1,001 - $15,000 Ron L Wyden 8000.5
... ... ... ... ... ... ... ... ...
7468 2016-01-06 Self UA Stock Purchase $50,001 - $100,000 John Hoeven 75000.5
7470 2016-11-23 Joint -- Stock Sale $1,001 - $15,000 Patrick J Toomey -8000.5
7471 2016-01-04 Joint -- Stock Sale $1,001 - $15,000 Patrick J Toomey -8000.5
7472 2016-01-05 Joint -- Stock Sale $15,001 - $50,000 Patrick J Toomey -32500.5
7473 2016-01-05 Joint -- Stock Purchase $1,001 - $15,000 Patrick J Toomey 8000.5

6539 rows × 8 columns

Alright, now we got some rough estimates of the value of each transaction, we can group trades together by date and find the aggregate for each day.

In [56]:
aggregate_action = df.groupby([pd.Grouper(key='transaction_date', freq='W'), 'asset_type', 'type']).sum()

# Groupby makes transaction_date and type an index, we want to convert those back into a column
aggregate_action.reset_index(inplace=True)

aggregate_action.head()
Out[56]:
transaction_date asset_type type mid_amt
0 2016-01-10 Municipal Security Purchase 97501.5
1 2016-01-10 Stock Purchase 495019.5
2 2016-01-10 Stock Sale -285506.0
3 2016-01-17 Municipal Security Purchase 750001.0
4 2016-01-17 Non-Public Stock Purchase 8000.5

We are now ready to plot senator trades against the market.

In [57]:
spy_hist['Date'] = spy_hist.index

# since we've limited the senator trades to a date range, we want to also limit SPY history
# to the same date range
market = spy_hist[(spy_hist['Date'] > start_date) & (spy_hist['Date'] < end_date)]

def plot_trades_vs_spy(trades, asset_type):

    # We have a lot of data, so we should make the figure very wide
    plt.figure(figsize=(30,10))

    plt.plot(market['Date'], market['Close'])

    plt.xlabel('Year')
    plt.ylabel('SPY price ($)')
    ax2 = plt.twinx()

    # scale bar graph limits s.t. 0 is centered in graph
    limit = max(abs(trades['mid_amt'].min()), trades['mid_amt'].max()) * 1.1
    ax2.set_ylim(-limit, limit)
    ax2.spines['bottom'].set_position(('data', 0))

    plt.ylabel('Amount of Securities Traded ($)')

    plt.bar(trades['transaction_date'], trades['mid_amt'], width=5, label='Net transaction', color='orange')
   
    plt.title('Senator Trades of ' + str(asset_type) + ' vs. SPY price')
    plt.legend()

    plt.show()

for asset_type in aggregate_action['asset_type'].unique():
    total = aggregate_action[aggregate_action['asset_type'] == asset_type]
    plot_trades_vs_spy(total, asset_type)

plot_trades_vs_spy(aggregate_action, 'Overall')

Let's also plot the net amount traded vs. future SPY price as well. We first need

In [59]:
import pandas_market_calendars as mcal
from datetime import datetime

nyse = mcal.get_calendar('NYSE')
market_open_days = nyse.valid_days(start_date=start_date, end_date=datetime.today().strftime('%Y-%m-%d'))

# returns a function that gets the spy price num_days from today
def get_future_spy_price(num_days):
    def h(today):
        # calculate current spy data
        today_index = market_open_days.get_loc(today, method='nearest')
        today_close = spy_hist.iloc[spy_hist.index.get_loc(today, method='nearest')]['Close']

        # calculate future date and get spy data
        future_index = today_index + num_days
        future_date = market_open_days[future_index]
        future_close = spy_hist.iloc[spy_hist.index.get_loc(future_date, method='nearest')]['Close']
        return (future_close - today_close) / today_close
    return h

aggregate_action['5_day_spy_pct_change'] = aggregate_action['transaction_date'].apply(get_future_spy_price(5))
aggregate_action['15_day_spy_pct_change'] = aggregate_action['transaction_date'].apply(get_future_spy_price(15))
# aggregate_total['30_day_spy_pct_change'] = aggregate_total['transaction_date'].apply(get_future_spy_price(30))
In [60]:
test = aggregate_action[abs(aggregate_action['mid_amt']) > 0]

for asset_type in test['asset_type'].unique():
    print(asset_type)
    testx = test[test['asset_type'] == asset_type]
    print(test.head())
    plt.figure(figsize=(30,10))
    plt.scatter(testx['mid_amt'], testx['5_day_spy_pct_change'])
    plt.xlabel('Estimated Amount of Securities Purchased/Sold')
    plt.show()

    plt.figure(figsize=(30,10))
    plt.scatter(testx['mid_amt'], testx['15_day_spy_pct_change'])
    plt.show()

    # plt.figure(figsize=(30,10))
    # plt.scatter(test['mid_amt'], test['30_day_spy_pct_change'])
    # plt.show()
Municipal Security
  transaction_date          asset_type      type   mid_amt  \
0       2016-01-10  Municipal Security  Purchase   97501.5   
1       2016-01-10               Stock  Purchase  495019.5   
2       2016-01-10               Stock      Sale -285506.0   
3       2016-01-17  Municipal Security  Purchase  750001.0   
4       2016-01-17    Non-Public Stock  Purchase    8000.5   

   5_day_spy_pct_change  15_day_spy_pct_change  
0             -0.021082              -0.010151  
1             -0.021082              -0.010151  
2             -0.021082              -0.010151  
3              0.011379              -0.013985  
4              0.011379              -0.013985  
Stock
  transaction_date          asset_type      type   mid_amt  \
0       2016-01-10  Municipal Security  Purchase   97501.5   
1       2016-01-10               Stock  Purchase  495019.5   
2       2016-01-10               Stock      Sale -285506.0   
3       2016-01-17  Municipal Security  Purchase  750001.0   
4       2016-01-17    Non-Public Stock  Purchase    8000.5   

   5_day_spy_pct_change  15_day_spy_pct_change  
0             -0.021082              -0.010151  
1             -0.021082              -0.010151  
2             -0.021082              -0.010151  
3              0.011379              -0.013985  
4              0.011379              -0.013985  
Non-Public Stock
  transaction_date          asset_type      type   mid_amt  \
0       2016-01-10  Municipal Security  Purchase   97501.5   
1       2016-01-10               Stock  Purchase  495019.5   
2       2016-01-10               Stock      Sale -285506.0   
3       2016-01-17  Municipal Security  Purchase  750001.0   
4       2016-01-17    Non-Public Stock  Purchase    8000.5   

   5_day_spy_pct_change  15_day_spy_pct_change  
0             -0.021082              -0.010151  
1             -0.021082              -0.010151  
2             -0.021082              -0.010151  
3              0.011379              -0.013985  
4              0.011379              -0.013985  
Corporate Bond
  transaction_date          asset_type      type   mid_amt  \
0       2016-01-10  Municipal Security  Purchase   97501.5   
1       2016-01-10               Stock  Purchase  495019.5   
2       2016-01-10               Stock      Sale -285506.0   
3       2016-01-17  Municipal Security  Purchase  750001.0   
4       2016-01-17    Non-Public Stock  Purchase    8000.5   

   5_day_spy_pct_change  15_day_spy_pct_change  
0             -0.021082              -0.010151  
1             -0.021082              -0.010151  
2             -0.021082              -0.010151  
3              0.011379              -0.013985  
4              0.011379              -0.013985  
Other Securities
  transaction_date          asset_type      type   mid_amt  \
0       2016-01-10  Municipal Security  Purchase   97501.5   
1       2016-01-10               Stock  Purchase  495019.5   
2       2016-01-10               Stock      Sale -285506.0   
3       2016-01-17  Municipal Security  Purchase  750001.0   
4       2016-01-17    Non-Public Stock  Purchase    8000.5   

   5_day_spy_pct_change  15_day_spy_pct_change  
0             -0.021082              -0.010151  
1             -0.021082              -0.010151  
2             -0.021082              -0.010151  
3              0.011379              -0.013985  
4              0.011379              -0.013985  
Stock Option
  transaction_date          asset_type      type   mid_amt  \
0       2016-01-10  Municipal Security  Purchase   97501.5   
1       2016-01-10               Stock  Purchase  495019.5   
2       2016-01-10               Stock      Sale -285506.0   
3       2016-01-17  Municipal Security  Purchase  750001.0   
4       2016-01-17    Non-Public Stock  Purchase    8000.5   

   5_day_spy_pct_change  15_day_spy_pct_change  
0             -0.021082              -0.010151  
1             -0.021082              -0.010151  
2             -0.021082              -0.010151  
3              0.011379              -0.013985  
4              0.011379              -0.013985  

Grouping By Senator

In [63]:
aggregate_action_by_senator = df.groupby([pd.Grouper(key='transaction_date', freq='D'), 'asset_type', 'type', 'senator']).sum()

# Groupby makes transaction_date and type an index, we want to convert those back into a column
aggregate_action_by_senator.reset_index(inplace=True)

# limit the dataset to a date range
aggregate_action_by_senator = aggregate_action_by_senator[(aggregate_action_by_senator['transaction_date'] > start_date) & (aggregate_action_by_senator['transaction_date'] < end_date)]

aggregate_action_by_senator['mid_amt'] = aggregate_action_by_senator.apply(lambda row: row['mid_amt'] if row['type'] == 'Purchase' else -row['mid_amt'], axis=1)

aggregate_action_by_senator['5_day_spy_pct_change'] = aggregate_action_by_senator['transaction_date'].apply(get_future_spy_price(5))
# aggregate_total['15_day_spy_pct_change'] = aggregate_total['transaction_date'].apply(get_future_spy_price(15))


    # plt.figure(figsize=(30,10))
    # plt.scatter(senator_actions['mid_amt'], testx['5_day_spy_pct_change'])
    # plt.xlabel('Estimated Amount of Securities Purchased/Sold')
    # plt.show()

    # plt.figure(figsize=(30,10))
    # plt.scatter(test['mid_amt'], test['15_day_spy_pct_change'])
    # plt.show()
In [64]:
print(aggregate_action_by_senator)

for senator in aggregate_action_by_senator['senator'].unique():

    senator_actions = aggregate_action_by_senator[aggregate_action_by_senator['senator'] == senator]
   
    plt.axvline(0, color='black')
    plt.axhline(0, color='black')
    plt.grid()

    plt.scatter(senator_actions['mid_amt'], senator_actions['5_day_spy_pct_change'])
    plt.show()
     transaction_date          asset_type      type             senator  \
0          2016-01-04               Stock      Sale    Patrick J Toomey   
1          2016-01-05  Municipal Security  Purchase     Lamar Alexander   
2          2016-01-05               Stock  Purchase    Patrick J Toomey   
3          2016-01-05               Stock  Purchase  Sheldon Whitehouse   
4          2016-01-05               Stock  Purchase     William Cassidy   
...               ...                 ...       ...                 ...   
2550       2020-10-13               Stock      Sale         Pat Roberts   
2551       2020-10-16               Stock  Purchase         Ron L Wyden   
2552       2020-10-27    Other Securities      Sale       Mark R Warner   
2553       2020-10-30    Other Securities  Purchase     Thomas R Carper   
2554       2020-10-30    Other Securities      Sale     Thomas R Carper   

        mid_amt  5_day_spy_pct_change  
0        8000.5             -0.044324  
1       32500.5             -0.038240  
2       24001.5             -0.038240  
3       96006.0             -0.038240  
4       16001.0             -0.038240  
...         ...                   ...  
2550    16001.0             -0.019279  
2551    48003.0             -0.004348  
2552  3000000.5             -0.006475  
2553    16001.0              0.072334  
2554     8000.5              0.072334  

[2555 rows x 6 columns]

Evaluating Every Single Trade

In [12]:
hists = {}

# returns a function that gets the spy price num_days from today
def get_future_stock_price(ticker, today, num_days):

    # print('Finding %change in price after', num_days, 'days for', ticker, 'on', today)

    try:
        stock_history = yf.Ticker(ticker).history(period='5y')

        # calculate current stock data
        today_index = market_open_days.get_loc(today, method='nearest')
        today_close = stock_history.iloc[stock_history.index.get_loc(today, method='nearest')]['Close']

        # calculate future date and get stock data
        future_index = today_index + num_days
        future_date = market_open_days[future_index]
        future_close = stock_history.iloc[stock_history.index.get_loc(future_date, method='nearest')]['Close']
        return (future_close - today_close) / today_close
    except Exception as e:
        return np.nan
In [13]:
stock_trades = df[df['ticker'] != '--']

# we're processing an insane amount of data here, so let's save this dataframe back to the disk
# so we can read it back easily
try:
    stock_trades = pd.read_csv('stock_trading_performance.csv')
except FileNotFoundError:
    print('calculating...')
    stock_trades['5_day_pct_change'] = stock_trades.apply(lambda row: get_future_stock_price(row['ticker'], row['transaction_date'], 5), axis=1)
    print('done with 5 day')
    stock_trades['15_day_pct_change'] = stock_trades.apply(lambda row: get_future_stock_price(row['ticker'], row['transaction_date'], 15), axis=1)
    print('done with 15 day')
    stock_trades['30_day_pct_change'] = stock_trades.apply(lambda row: get_future_stock_price(row['ticker'], row['transaction_date'], 30), axis=1)
    print('done with 15 day')
    # stock_trades.apply(lambda row: get_future_stock_price(row['ticker'], row['transaction_date'], 5), axis=1)
    stock_trades.to_csv('stock_trading_performance.csv')
In [14]:
print(stock_trades['owner'].unique())
print(len(stock_trades['senator'].unique()))
['Spouse' 'Child' 'Joint' 'Self']
39
In [15]:
stock_trades['5_day_pct_change'] = pd.to_numeric(stock_trades['5_day_pct_change'], errors='coerce')
stock_trades['15_day_pct_change'] = pd.to_numeric(stock_trades['15_day_pct_change'], errors='coerce')

for senator in stock_trades['senator'].unique():
    for owner in stock_trades['owner'].unique():
        print(senator, owner)

        stock_trades_by_senator = stock_trades[(stock_trades['senator'] == senator) & (stock_trades['owner'] == owner)]

        plt.scatter(stock_trades_by_senator['mid_amt'], stock_trades_by_senator['5_day_pct_change'])
        plt.show()
# plt.scatter(stock_trades['mid_amt'], stock_trades['5_day_pct_change'])
# plt.show()
# plt.scatter(stock_trades['mid_amt'], stock_trades['15_day_pct_change'])
William Cassidy Spouse
William Cassidy Child
William Cassidy Joint
William Cassidy Self
Ron L Wyden Spouse
Ron L Wyden Child
Ron L Wyden Joint
Ron L Wyden Self
Pat Roberts Spouse
Pat Roberts Child
Pat Roberts Joint
Pat Roberts Self
Thomas R Carper Spouse
Thomas R Carper Child
Thomas R Carper Joint
Thomas R Carper Self
Sheldon Whitehouse Spouse
Sheldon Whitehouse Child
Sheldon Whitehouse Joint
Sheldon Whitehouse Self
Angus S King, Jr. Spouse
Angus S King, Jr. Child
Angus S King, Jr. Joint
Angus S King, Jr. Self
A. Mitchell Mcconnell, Jr. Spouse
A. Mitchell Mcconnell, Jr. Child
A. Mitchell Mcconnell, Jr. Joint
A. Mitchell Mcconnell, Jr. Self
Patrick J Toomey Spouse
Patrick J Toomey Child
Patrick J Toomey Joint
Patrick J Toomey Self
Jerry Moran, Spouse
Jerry Moran, Child
Jerry Moran, Joint
Jerry Moran, Self
Kelly Loeffler Spouse
Kelly Loeffler Child
Kelly Loeffler Joint
Kelly Loeffler Self
James M Inhofe Spouse
James M Inhofe Child
James M Inhofe Joint
James M Inhofe Self
Timothy M Kaine Spouse
Timothy M Kaine Child
Timothy M Kaine Joint
Timothy M Kaine Self
Roy Blunt Spouse
Roy Blunt Child
Roy Blunt Joint
Roy Blunt Self
Shelley M Capito Spouse
Shelley M Capito Child
Shelley M Capito Joint
Shelley M Capito Self
Daniel S Sullivan Spouse
Daniel S Sullivan Child
Daniel S Sullivan Joint
Daniel S Sullivan Self
David A Perdue , Jr Spouse
David A Perdue , Jr Child
David A Perdue , Jr Joint
David A Perdue , Jr Self
Roger F Wicker Spouse
Roger F Wicker Child
Roger F Wicker Joint
Roger F Wicker Self
Tina Smith Spouse
Tina Smith Child
Tina Smith Joint
Tina Smith Self
John Hoeven Spouse
John Hoeven Child
John Hoeven Joint
John Hoeven Self
John N Kennedy Spouse
John N Kennedy Child
John N Kennedy Joint
John N Kennedy Self
Rafael E Cruz Spouse
Rafael E Cruz Child
Rafael E Cruz Joint
Rafael E Cruz Self
Susan M Collins Spouse
Susan M Collins Child
Susan M Collins Joint
Susan M Collins Self
Thomas R Tillis Spouse
Thomas R Tillis Child
Thomas R Tillis Joint
Thomas R Tillis Self
Christopher A Coons Spouse
Christopher A Coons Child
Christopher A Coons Joint
Christopher A Coons Self
Gary C Peters Spouse
Gary C Peters Child
Gary C Peters Joint
Gary C Peters Self
Jacklyn S Rosen Spouse
Jacklyn S Rosen Child
Jacklyn S Rosen Joint
Jacklyn S Rosen Self
Thomas Udall Spouse
Thomas Udall Child
Thomas Udall Joint
Thomas Udall Self
John F Reed Spouse
John F Reed Child
John F Reed Joint
John F Reed Self
Mark R Warner Spouse
Mark R Warner Child
Mark R Warner Joint
Mark R Warner Self
Ladda Tammy Duckworth Spouse
Ladda Tammy Duckworth Child
Ladda Tammy Duckworth Joint
Ladda Tammy Duckworth Self
Robert P Casey, Jr. Spouse
Robert P Casey, Jr. Child
Robert P Casey, Jr. Joint
Robert P Casey, Jr. Self
Tammy Duckworth Spouse
Tammy Duckworth Child
Tammy Duckworth Joint
Tammy Duckworth Self
Michael F Bennet Spouse
Michael F Bennet Child
Michael F Bennet Joint
Michael F Bennet Self
Patty Murray Spouse
Patty Murray Child
Patty Murray Joint
Patty Murray Self
Joseph Manchin, Iii Spouse
Joseph Manchin, Iii Child
Joseph Manchin, Iii Joint
Joseph Manchin, Iii Self
Chris Van Hollen Spouse
Chris Van Hollen Child
Chris Van Hollen Joint
Chris Van Hollen Self
John Cornyn Spouse
John Cornyn Child
John Cornyn Joint
John Cornyn Self
Maria Cantwell Spouse
Maria Cantwell Child
Maria Cantwell Joint
Maria Cantwell Self
Michael  B Enzi Spouse
Michael  B Enzi Child
Michael  B Enzi Joint
Michael  B Enzi Self
In [16]:
for senator in stock_trades['senator'].unique():
    stock_trades_by_senator = stock_trades[stock_trades['senator'] == senator]

    fig, axs = plt.subplots(1, 2, figsize=(12, 5))
    fig.suptitle('Trade Value vs. Future Stock Price % Change for Senator ' + senator)

    axs[0].scatter(stock_trades_by_senator['mid_amt'], stock_trades_by_senator['5_day_pct_change'])
    axs[0].set_title('5 Day')
    axs[0].set_xlabel('Net Value of Assets Bought/Sold')
    axs[0].set_ylabel('5 Day % Change in Stock Price')
    axs[1].scatter(stock_trades_by_senator['mid_amt'], stock_trades_by_senator['15_day_pct_change'])
    axs[1].set_title('15 Day')
    axs[1].set_xlabel('Net Value of Assets Bought/Sold')
    axs[1].set_ylabel('15 Day % Change in Stock Price')

    axs[0].grid()
    axs[1].grid()

    # plt.
    # plt.title('Trade vs. 5 Day Future Stock Price % Change for Senator ' + senator)
    plt.show()
In [ ]: